﻿using System;
using System.Security.Cryptography;
using System.Text;
using System.Security;
using System.Web.UI;
using System.IO;
using System.Web.SessionState;
using System.Web;
using System.Collections;
using DTN.Core.Utilities;

namespace com.dtn.deals.Sercurity
{
    public class SecurityMethod
    {
        static string passPhrase = "123";        // can be any string
        static string saltValue = "s@1tValue";        // can be any string
        static string hashAlgorithm = "SHA1";             // can be "MD5"
        static int passwordIterations = 2;                  // can be any number
        static string initVector = "@1B2c3D4e5F6g7H8"; // must be 16 bytes
        static int keySize = 256;

        private const string signatureSecurityCode = "Q@#RWLKUFHSDLJKF234234SLDKBJ34VCXLKJHLIRU234235";
        private static ArrayList InMemorySignStore = null;
        public static string GenSalt()
        {
            return GenSalt(3);
        }

        public static string GenSalt(int len)
        {
            string salt = "";
            Random r = new Random(DateTime.Now.Millisecond);

            for (int i = 0; i < len; i++)
            {
                int ran = r.Next(33, 126);
                salt += ((char)ran).ToString();
            }
            return salt;
        }
        public static string EncryptTicket(Ticket ticket)
        {
            string strSealed = Serialization.SerializeObject(ticket);
            return SecurityMethod.EncryptString(strSealed, passPhrase, saltValue, hashAlgorithm, passwordIterations, initVector, keySize);
        }
        public static string EncryptString(string plainText,
                                 string passPhrase,
                                 string saltValue,
                                 string hashAlgorithm,
                                 int passwordIterations,
                                 string initVector,
                                 int keySize)
        {
            // Convert strings into byte arrays.
            // Let us assume that strings only contain ASCII codes.
            // If strings include Unicode characters, use Unicode, UTF7, or UTF8 
            // encoding.
            byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);

            // Convert our plaintext into a byte array.
            // Let us assume that plaintext contains UTF8-encoded characters.
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

            // First, we must create a password, from which the key will be derived.
            // This password will be generated from the specified passphrase and 
            // salt value. The password will be created using the specified hash 
            // algorithm. Password creation can be done in several iterations.
            PasswordDeriveBytes password = new PasswordDeriveBytes(
                                                            passPhrase,
                                                            saltValueBytes,
                                                            hashAlgorithm,
                                                            passwordIterations);

            // Use the password to generate pseudo-random bytes for the encryption
            // key. Specify the size of the key in bytes (instead of bits).
            byte[] keyBytes = password.GetBytes(keySize / 8);

            // Create uninitialized Rijndael encryption object.
            RijndaelManaged symmetricKey = new RijndaelManaged();

            // It is reasonable to set encryption mode to Cipher Block Chaining
            // (CBC). Use default options for other symmetric key parameters.
            symmetricKey.Mode = CipherMode.CBC;

            // Generate encryptor from the existing key bytes and initialization 
            // vector. Key size will be defined based on the number of the key 
            // bytes.
            ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
                                                             keyBytes,
                                                             initVectorBytes);

            // Define memory stream which will be used to hold encrypted data.
            MemoryStream memoryStream = new MemoryStream();

            // Define cryptographic stream (always use Write mode for encryption).
            CryptoStream cryptoStream = new CryptoStream(memoryStream,
                                                         encryptor,
                                                         CryptoStreamMode.Write);
            // Start encrypting.
            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);

            // Finish encrypting.
            cryptoStream.FlushFinalBlock();

            // Convert our encrypted data from a memory stream into a byte array.
            byte[] cipherTextBytes = memoryStream.ToArray();

            // Close both streams.
            memoryStream.Close();
            cryptoStream.Close();

            // Convert encrypted data into a base64-encoded string.
            string cipherText = Convert.ToBase64String(cipherTextBytes);

            // Return encrypted string.
            return cipherText;
        }
        public static string EncryptString(string value, Page oPage)
        {
            //System.Security.Cryptography.TripleDESCryptoServiceProvider o3DES = new System.Security.Cryptography.TripleDESCryptoServiceProvider();
            //o3DES.GenerateKey();
            //o3DES.GenerateIV();
            //oPage.Session["Key"] = o3DES.Key;
            //oPage.Session["IV"] = o3DES.IV;

            if (oPage.Session["Key"] != null && oPage.Session["IV"] != null)
                return EncryptString(value, (byte[])oPage.Session["Key"], (byte[])oPage.Session["IV"]);
            else
                return null;
        }

        public static string EncryptString(string value, byte[] oKey, byte[] oIV)
        {
            if (value != "")
            {
                TripleDESCryptoServiceProvider oCryptoProvider = new TripleDESCryptoServiceProvider();
                MemoryStream oMemoryStream = new MemoryStream();
                CryptoStream oCryptoStream = new CryptoStream(oMemoryStream, oCryptoProvider.CreateEncryptor(oKey, oIV), CryptoStreamMode.Write);
                StreamWriter sw = new StreamWriter(oCryptoStream);
                sw.Write(value);
                sw.Flush();
                oCryptoStream.FlushFinalBlock();
                oMemoryStream.Flush();
                return Convert.ToBase64String(oMemoryStream.GetBuffer(), 0, (int)oMemoryStream.Length);
            }
            return "";
        }

        public static string DecryptString(string value, HttpSessionState oS)
        {
            if (oS["Key"] != null && oS["IV"] != null)
                return DecryptString(value, (byte[])oS["Key"], (byte[])oS["IV"]);
            else
                return null;
        }

        public static string DecryptString(string value, byte[] oKey, byte[] oIV)
        {
            if (value != "")
            {
                TripleDESCryptoServiceProvider ooCryptoProvider = new TripleDESCryptoServiceProvider();
                byte[] buffer = Convert.FromBase64String(value);
                MemoryStream oMemStream = new MemoryStream(buffer);
                CryptoStream oCryptoStream = new CryptoStream(oMemStream, ooCryptoProvider.CreateDecryptor(oKey, oIV), CryptoStreamMode.Read);
                StreamReader sr = new StreamReader(oCryptoStream);
                return sr.ReadToEnd();
            }
            else return "";

        }

        public static string RandomString(int length)
        {
            string str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            int strlen = str.Length;
            Random rnd = new Random();
            string retVal = String.Empty;

            for (int i = 0; i < length; i++)
                retVal += str[rnd.Next(strlen)];

            return retVal;
        }

        public static string MD5Encrypt(string plainText)
        {
            byte[] textBytes = System.Text.Encoding.Default.GetBytes(plainText);
            try
            {
                System.Security.Cryptography.MD5CryptoServiceProvider cryptHandler;
                cryptHandler = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] hash = cryptHandler.ComputeHash(textBytes);
                string ret = "";
                foreach (byte a in hash)
                {
                    ret += a.ToString("x2");
                }
                return ret;
            }
            catch
            {
                throw;
            }


        }

        public static string MD5EncryptOld(string plainText)
        {
            byte[] data, output;
            UTF8Encoding encoder = new UTF8Encoding();
            MD5CryptoServiceProvider hasher = new MD5CryptoServiceProvider();

            data = encoder.GetBytes(plainText);
            output = hasher.ComputeHash(data);

            return BitConverter.ToString(output).Replace("-", "").ToLower();

        }


        public static string RandomPassword()
        {
            string retVal = String.Empty;
            Random rd = new Random(DateTime.Now.Millisecond);
            for (int i = 1; i < 10; i++)
            {
                retVal += rd.Next(0, 9);
            }
            return retVal;
        }

        public const string SecureAnswerPassword = ")&*%^^%%^##$%@#@@~_|+{:))(*)*&%HJGsdsd";

        public static string DESEncrypt(string plainText, string password)
        {
            string encrypted;
            TripleDESCryptoServiceProvider des;
            MD5CryptoServiceProvider hash;
            byte[] pwdhash, buff;

            hash = new MD5CryptoServiceProvider();
            pwdhash = hash.ComputeHash(UnicodeEncoding.Unicode.GetBytes(password));
            hash = null;

            des = new TripleDESCryptoServiceProvider();
            des.Key = pwdhash;
            des.Mode = CipherMode.ECB;

            buff = UnicodeEncoding.Unicode.GetBytes(plainText);
            encrypted = Convert.ToBase64String(des.CreateEncryptor().TransformFinalBlock(buff, 0, buff.Length));

            des = null;
            return encrypted;
        }

        public static string DESDecrypt(string encrypted, string password)
        {
            string decrypted;
            TripleDESCryptoServiceProvider des;
            MD5CryptoServiceProvider hash;
            byte[] pwdhash, buff;

            hash = new MD5CryptoServiceProvider();
            pwdhash = hash.ComputeHash(UnicodeEncoding.Unicode.GetBytes(password));
            hash = null;

            des = new TripleDESCryptoServiceProvider();
            des.Key = pwdhash;
            des.Mode = CipherMode.ECB;

            buff = Convert.FromBase64String(encrypted);
            decrypted = UnicodeEncoding.Unicode.GetString(des.CreateDecryptor().TransformFinalBlock(buff, 0, buff.Length));
            des = null;
            return decrypted;
        }
        
        public static Ticket DecryptTicket(string encryptedData)
        {
            string decryptedData =
                SecurityMethod.DecryptString(encryptedData, passPhrase, saltValue, hashAlgorithm, passwordIterations,
                                             initVector, keySize);
            return (Ticket)Serialization.DeserializeObject(decryptedData, typeof(Ticket));
        }
        public static string DecryptString(string cipherText,
                                    string passPhrase,
                                    string saltValue,
                                    string hashAlgorithm,
                                    int passwordIterations,
                                    string initVector,
                                    int keySize)
        {
            // Convert strings defining encryption key characteristics into byte
            // arrays. Let us assume that strings only contain ASCII codes.
            // If strings include Unicode characters, use Unicode, UTF7, or UTF8
            // encoding.
            byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);

            // Convert our ciphertext into a byte array.
            byte[] cipherTextBytes = Convert.FromBase64String(cipherText);

            // First, we must create a password, from which the key will be 
            // derived. This password will be generated from the specified 
            // passphrase and salt value. The password will be created using
            // the specified hash algorithm. Password creation can be done in
            // several iterations.
            PasswordDeriveBytes password = new PasswordDeriveBytes(
                                                            passPhrase,
                                                            saltValueBytes,
                                                            hashAlgorithm,
                                                            passwordIterations);

            // Use the password to generate pseudo-random bytes for the encryption
            // key. Specify the size of the key in bytes (instead of bits).
            byte[] keyBytes = password.GetBytes(keySize / 8);

            // Create uninitialized Rijndael encryption object.
            RijndaelManaged symmetricKey = new RijndaelManaged();

            // It is reasonable to set encryption mode to Cipher Block Chaining
            // (CBC). Use default options for other symmetric key parameters.
            symmetricKey.Mode = CipherMode.CBC;

            // Generate decryptor from the existing key bytes and initialization 
            // vector. Key size will be defined based on the number of the key 
            // bytes.
            ICryptoTransform decryptor = symmetricKey.CreateDecryptor(
                                                             keyBytes,
                                                             initVectorBytes);

            // Define memory stream which will be used to hold encrypted data.
            MemoryStream memoryStream = new MemoryStream(cipherTextBytes);

            // Define cryptographic stream (always use Read mode for encryption).
            CryptoStream cryptoStream = new CryptoStream(memoryStream,
                                                          decryptor,
                                                          CryptoStreamMode.Read);

            // Since at this point we don't know what the size of decrypted data
            // will be, allocate the buffer long enough to hold ciphertext;
            // plaintext is never longer than ciphertext.
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];

            // Start decrypting.
            int decryptedByteCount = cryptoStream.Read(plainTextBytes,
                                                       0,
                                                       plainTextBytes.Length);

            // Close both streams.
            memoryStream.Close();
            cryptoStream.Close();

            // Convert decrypted data into a string. 
            // Let us assume that the original plaintext string was UTF8-encoded.
            string plainText = Encoding.UTF8.GetString(plainTextBytes,
                                                       0,
                                                       decryptedByteCount);

            // Return decrypted string.   
            return plainText;
        }
    }
}